home *** CD-ROM | disk | FTP | other *** search
- /*
- * RTMP / ZIP etc.
- *
- * (c) 1986, Stanford Univ. CSLI.
- * May be used but not sold without permission.
- *
- * $Header: rtmp.c,v 4.1 88/11/01 19:51:00 sw0l Locked $
- */
-
- #include "gw.h"
- #include "gwctl.h"
- #include "fp/pbuf.h"
- #include "ab.h"
- #include "inet.h"
- #include "fp/cmdmacro.h"
-
- #include "glob.h"
- extern u_char broadcastaddr[];
-
- #ifdef SNMP
- #include "mib.h"
- #include "snmp_vars.h"
- #endif
-
-
- short rtmp_delay, rtmp_vdelay; /* 'static' */
-
- short art_delay; /* 'static' */
- short zip_delay;
- struct aroute *notzipped;
- struct aroute *art_last; /* 'static', last aroute pointer */
-
- /*
- * RTMP clock routine.
- * Broadcasts RTMP's on AppleTalk segment, age routes.
- */
- rtmptimer()
- {
- register struct aroute *ar;
- int i;
-
- if (rtmp_delay && ++rtmp_delay < 11)
- return; /* run only every 10 seconds */
-
- rtmp_delay = 1;
-
- /* broadcast the current routing table on appletype interfaces */
- for (i = 0 ; i < MAX_PORT; i++)
- if (porttoif[i] && porttoif[i]->if_flags & IF_APPLETYPE)
- rtmpsend(porttoif[i]);
-
- if (rtmp_vdelay++ == 0) /* validity timer goes off every 20 secs */
- return;
- rtmp_vdelay = 0;
- /* age routes in our table */
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0 || ar->hops == 0 || (ar->flags & arouteAA))
- continue;
- if (arouteBad(ar)) {
- ar->net = 0; /* delete it */
- continue;
- }
- if (ar->age < 255)
- ar->age++;
- }
- }
-
-
- /*
- * Send an RTMP packet. If 'tuples' is true,
- * include the routing tuples.
- */
- /* break into send and reply */
-
- /* rtmp send: used only to broadcast rtmp "here I ams" */
- /* setup for ddp reply and call rtmpreply */
- rtmpsend(ifp)
- struct ifnet *ifp;
- {
- source_if = ifp;
- ddp.srcNet = source_if->if_dnet;
- ddp.srcNode = 0xff; /* broadcast */
- ddp.srcSkt = rtmpSkt;
- rtmpreply(1);
- }
-
- /* rtmp reply - reply to last packet (was rtmp request) */
- rtmpreply(tuples)
- {
- register struct pbuf *p;
- register struct RTMP *r;
- register i;
-
- K_PGET(PT_DATA, p);
- if (p == 0)
- return;
- r = (struct RTMP *)(p->p_off + lapSize + ddpSize);
- r->net = source_if->if_dnet;
- r->idLen = 8;
- r->id = source_if->if_dnode;
- if (tuples)
- i = rtmpsettuples((caddr_t)(r + 1));
- else
- i = 0;
- /* setup for ddp send */
- ddp.type = ddpRTMP; /* in case request */
- p->p_len = i+rtmpSize+ddpSize+lapSize;
- ddpreply(p, rtmpSkt);
- }
-
-
- /*
- * Merge new routing tuples into our aroute table.
- */
- rtmpmerge(cp, count, sender)
- register unsigned char *cp; /* start of tuple array [3][n] */
- int count; /* count of tuples */
- int sender; /* node of tuple sender */
- {
- struct arouteTuple at;
- int port;
-
- at.node = sender;
- port = source_if->if_unit;
- for ( ; count > 0 ; count--) {
- at.net = (*cp)<<8|(*(cp+1));
- at.hops = *(cp+2);
- at.flags = 0;
- cp+=3; /* advance */
- newroute(&at, port);
- }
- }
-
- newroute(at, port)
- register struct arouteTuple *at;
- int port;
- {
- struct aroute *arfree = 0;
- register struct aroute *ar;
-
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0) { /* remember a free slot */
- if (arfree == 0) arfree = ar;
- continue;
- }
- if (at->net == ar->net) {
- /* search for this tuple net in table */
- /* [want check inside so we drop the extra aaroutes] */
- if (ar->hops == 0) /* never touch local entries */
- return;
- if (arouteBad(ar) && at->hops < 15)
- goto replace;
- if (ar->hops >= (at->hops+1) && at->hops < 15)
- goto replace;
- if (ar->node == at->node && port == ar->port) {
- if ((ar->hops = at->hops + 1) < 16)
- ar->age = 0;
- else
- ar->net = 0;
- }
- return;
- }
- }
- /* add */
- /* tuple net # wasnt in our table, add it */
- if ((ar = arfree) == 0)
- return; /* oops, out of room */
- arfree = 0;
- /* until we implment zip takedown, bringup, it's probably best to */
- /* to put zone setting in "replace", but .... */
- ar->zone = 0;
- if (!notzipped)
- notzipped = ar;
- replace:
- ar->net = at->net;
- ar->hops = at->hops + 1;
- ar->node = at->node;
- ar->port = port;
- ar->age = 0;
- ar->flags = at->flags;
- }
-
-
- /*
- * Setup a tuple array, starting at cp; returns total size
- * of the array in bytes.
- */
- rtmpsettuples(cp)
- register char *cp;
- {
- register count;
- register struct aroute *ar;
-
- count = 0;
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0 || arouteBad(ar))
- continue;
- if (ar->zone == 0 && notzipped == 0)
- notzipped = ar;
- /* copy in the net, hops, but be careful of byte aligment */
- *cp++ = ar->net >> 8;
- *cp++ = ar->net & 0xff;
- *cp++ = ar->hops;
- count += 3;
- }
- return (count);
- }
-
-
- /*
- * RTMP received from AppleTalk.
- */
- rtmpinput(p)
- struct pbuf *p;
- {
- register struct RTMP *r;
- register tbytes, tuples;
- int src;
-
- p->p_len -= (lapSize+ddpSize); /* skip lap+ddp */
- p->p_off += (lapSize+ddpSize);
-
- /* rtmp from ourselfs */
- if ((ddp.dstNet == source_if->if_dnet && ddp.dstNode==source_if->if_dnode) ||
- p->p_len < 1)
- goto drop;
-
- if (ddp.type == ddpRTMPR) {
- /* RTMP request from Mac trying to get his net # */
- if (*p->p_off != 1)
- goto drop; /* only opcode defined now is 1 */
- rtmpreply(0); /* reply */
- goto drop;
- }
-
- r = (struct RTMP *)p->p_off;
- src = r->id;
- if (p->p_len < sizeof(struct RTMP) ||
- (tbytes = ddp.length-ddpSize-sizeof(struct RTMP)) <= 0 ||
- r->idLen != 8 || r->id == source_if->if_dnode)
- goto drop;
-
- if ((tuples = tbytes/3)) /* if we have any tuples, merge them in */
- rtmpmerge((caddr_t)(r+1), tuples, src);
- drop:
- K_PFREE(p);
- }
-
-
- /*
- * Send arouteTuple's to gateway at 'ia'.
- * If 'all' flag is true, sends all routes not configured by AA.
- * If 'all' is 0, only sends locally discovered routes (new atalk
- * segments dynamically plugged in).
- */
- artsend(ia, all)
- iaddr_t ia;
- register all;
- {
- register struct aroute *ar;
- register struct arouteTuple *at;
- struct pbuf *p;
- register count;
-
- count = 0;
- K_PGET(PT_DATA, p);
- if (p == 0)
- return(0);
- at = (struct arouteTuple *)m_stuff(p->p_off);
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0 || ar->hops == 0)
- continue; /* skip null & local entries */
- if (all) {
- if (ar->flags & arouteAA)
- continue; /* skip AA entries */
- } else {
- if (arouteIP(ar))
- continue; /* skip IP entries */
- }
-
- if (arouteIP(ar)) {
- at->node = ar->node;
- at->flags = ar->flags;
- } else {
- /* if node was an atalk address, subst. our IP addr */
- at->node = conf.ipaddr;
- at->flags = arouteKbox;
- }
- at->net = ar->net;
- at->hops = ar->hops;
- at++;
- count++;
- }
- if (count == 0 && all)
- goto drop; /* dont sent null aaROUTE packets */
- kipit(p, ia, all ? aaROUTE : aaROUTEQ, count * sizeof *at);
- /* (but we would send a null aaROUTEQ query packet) */
- return (1);
- drop:
- K_PFREE(p);
- return (0);
- }
-
-
- /*
- * arouteTuple timer routine. Once per minute send arouteTuple's
- * to 'core' gateways.
- */
- arttimer()
- {
- register struct aroute *ar;
- register count;
-
- if (art_delay && ++art_delay < 60)
- return; /* run only every 60 seconds */
- art_delay = 1;
- if (arouteinit == 0) {
- /* if routes not yet received from AA */
- confrequest(aaROUTEI);
- }
- /*
- * send local additions to one of the core's,
- * chosen circularly.
- */
- if ((ar = art_last) == 0)
- ar = &aroute[0];
- for (count = 0 ; count < NAROUTE ; count++) {
- ar++;
- if (ar >= &aroute[NAROUTE])
- ar = &aroute[0];
- if (ar->net == 0 || (ar->flags & arouteCore) == 0)
- continue;
- art_last = ar;
- artsend(ar->node, 0);
- return;
- }
- /* else no core gateways found */
- return;
- }
-
-
- /*
- * arouteTuples received from another gateway or AA.
- * Merge into our table and send reply if requested.
- */
- artinput(aa, ipsrc)
- register struct aaconf *aa;
- iaddr_t ipsrc;
- {
- register struct arouteTuple *at;
- register struct aroute *ar;
- register count, type;
-
- if ((type = aa->type) == aaROUTEI) {
- /* if init table from AA, clear all entries */
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar)
- if (ar->flags & arouteAA)
- ar->net = 0;
- }
- at = (struct arouteTuple *)aa->stuff;
- for (count = aa->count / sizeof *at ; count > 0 ; count--, at++) {
- if (type == aaROUTEI)
- at->flags |= arouteAA;
- newroute(at, 1); /* 1 is the ip port */
- }
- if (type == aaROUTEQ)
- artsend(ipsrc, 1);
- else if (type == aaROUTEI) {
- artsend(ipsrc, 0);
- arouteinit = 1;
- }
- }
-
-
- /*
- * Get the aroute entry corresponding to the atalk net number
- * supplied. Returns 0 if not routed via LocalTalk, otherwise the bridge's
- * node number on our atalk segment (or -1 if local segment).
- */
- getaroute(net)
- register net;
- {
- register struct aroute *ar;
-
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE] ; ++ar) {
- if (ar->net == 0 || ar->net != net) /* empty slot */
- continue;
- /* not a LocalTalk port or invalid port */
- /* if (ar->port > MAX_PORT) return(0); - paranoia */
- if (!porttoif[ar->port] || (porttoif[ar->port]->if_flags & IF_ALAP) == 0)
- return(0);
- return(ar->node ? ar->node : -1);
- }
- return (0);
- }
-
-
- /*
- * Ziptimer; gets aaZONE table from AA. Perhaps should
- * also zipQuery unzoned nets...
- */
- ziptimer()
- {
- if (arouteinit == 0)
- return; /* wait until routing table received */
- #ifdef notdef
- if (azoneinit == 0) { /* if aaZONE not yet received */
- confrequest(aaZONE);
- return;
- }
- #endif
-
- if (notzipped == 0 || (zip_delay && ++zip_delay < 5)) /* once every 5 sec*/
- return;
- zip_delay = 1;
-
- zipquery();
- }
-
- zipquery()
- {
- struct pbuf *p;
- register struct aroute *ar;
- struct ZIP *z;
- u_short *n;
- int count;
- u_char port;
- long node;
- int toadmin = 0;
-
- if (notzipped == 0)
- return;
- if (notzipped->zone) {
- notzipped = 0;
- return;
- }
- K_PGET(PT_DATA, p);
- if (p == 0)
- return;
- port = notzipped->port;
- node = notzipped->node;
- /* necessary to fake ddp reply */
- source_if = porttoif[notzipped->port];
- if (source_if->if_flags & IF_IPUDP) {
- toadmin = (notzipped->flags & arouteAA) || notzipped->hops == 0 ;
- z = (struct ZIP *)m_stuff(p->p_off);
- count = sizeof(struct ZIP);
- } else {
- /* pretend replying to bridge that advertised this rtmp */
- ddp.srcNet = source_if->if_dnet;
- ddp.srcNode = notzipped->node;
- ddp.srcSkt = zipSkt;
- ddp.type = ddpZIP;
- count = sizeof(struct ZIP);
- z = (struct ZIP *)(p->p_off + lapSize + ddpSize);
- }
- z->command = zipQuery;
- z->count = 0;
- n = (u_short *)(z+1); /* point to start of nets */
- notzipped = 0;
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE]; ++ar) {
- if (ar->net && ar->zone == 0) {
- if (!toadmin) {
- if (ar->node != node || ar->port != port) {
- if (!notzipped) /* if no new selection */
- notzipped = ar; /* try one! */
- continue;
- }
- } else if ((ar->flags & arouteAA) == 0 && ar->hops != 0)
- continue;
- *n = ar->net;
- n++;
- z->count++;
- count +=2;
- }
- }
- if (source_if->if_flags & IF_IPUDP) {
- kipit(p, toadmin ? conf.ipadmin : node, aaZONEQ, count);
- } else {
- p->p_len = lapSize+ddpSize+count;
- ddpreply(p, zipSkt);
- }
- }
-
-
- u_char *azonep;
- int numzones;
-
- newzone(s)
- u_char *s;
- {
- u_char i;
- int zi;
-
- if (azonep == 0)
- azonep = azonenames;
- if ((zi=zipfind(s, 0)) > 0)
- return(zi);
- if (numzones >= (NAZONE-2)) /* no more room */
- return(0);
- i = *s++; /* get the length */
- if ((i + azonep + 2) > (azonenames+sizeof(azonenames))) /* check it */
- return(0);
- azone[++numzones] = azonep; /* set dp */
- azone[numzones+1] = 0; /* tie off end */
- *azonep++ = i;
- /* Check for special zone that gets all requests */
- if (strncmp(s, ALLZONES, i) == 0)
- allzones = numzones;
- bcopy(s, azonep, i);
- azonep += i;
- return(numzones); /* return index */
- }
-
- #ifdef notdef
- /*
- * Called from ip4me() when aaZONE arrives from AA.
- * Setup our zone table and zone indexes in aroute.
- */
- zipinit(aa)
- struct aaconf *aa;
- {
- register u_char *cp,*ncp;
- register i,l,iz;
- register unsigned n;
-
-
- /*
- * parse aaZONE table; format:
- * net# net# ... 0 zonename
- * net# net# ... 0 zonename
- * 0xFFFF
- */
- for (cp = aa->stuff;;) {
- ncp = cp;
- do {
- n = *cp++;
- n <<= 8;
- n |= *cp++;
- } while (n && n != 0xffff);
- if (n == 0xFFFF)
- break; /* end of table */
- l = *cp; /* length of str */
- iz = newzone(cp);
- if (iz == 0) /* no more room */
- break;
- /* Check for special zone that gets all requests */
- if (strncmp(cp+1, ALLZONES, l) == 0)
- allzones = iz;
- do {
- n = *ncp++;
- n <<= 8;
- n |= *ncp++;
- if (n == 0)
- break;
- for (i = 0 ; i < NAROUTE ; ++i)
- if (n == aroute[i].net)
- break;
- if (i < NAROUTE)
- aroute[i].zone = iz;
- } while (n);
- cp += l + 1;
- }
- /* end of table */
- azone[0] = azone[aroute[0].zone]; /* my own zone */
- azoneinit = 1; /* dont ask for aaZONE anymore */
- }
- #endif
-
- /*
- * Find the zone index, given the name; returns -1 if not found.
- * set flag true if want (conf.flags).
- */
- zipfind(s, flag)
- register u_char *s;
- int flag;
- {
- register i;
-
- for (i = 1 ; ; i++) {
- if (azone[i] == 0)
- return (-1); /* reached end of table */
- if (*azone[i] != *s) /* lengths must match */
- continue;
- if (strncmpci(s+1, azone[i]+1, *s) != 0)
- continue;
- if (flag && (conf.flags & conf_stayinzone))
- if (aroute[0].zone && azone[i] != azone[aroute[0].zone])
- return (-1);
- return (i);
- }
- }
-
- /*
- * String compare, case independent;
- * returns zero if equal, one otherwise
- */
- strncmpci(s,t,n)
- char *s,*t;
- int n;
- {
- register char c,d;
-
- while (n--) {
- c = *s++;
- if (c >= 'A' && c <= 'Z')
- c += ('a'-'A'); /* convert to lower case */
- d = *t++;
- if (d >= 'A' && d <= 'Z')
- d += ('a'-'A'); /* convert to lower case */
- if (c != d)
- return(1);
- if (c == '\0')
- return(0);
- }
- return(0); /* success on runnout */
- }
-
-
- /*
- * Process ZIP packet received on input.
- */
- zipatp(ip)
- struct pbuf *ip;
- {
- union zipatp {
- struct ATP a; /* atp */
- u_char c[sizeof(struct ATP)]; /* 8 bytes */
- u_short s[sizeof(struct ATP)/sizeof(u_short)]; /* 4 words */
- } zipatp, *zap;
- u_char *po, *pi;
- int zl; /* zone length */
- int zi; /* zone index */
- int fzones; /* # of found zones */
- int len, count, i,j ;
- register struct aroute *ar;
-
- /* we can reuse the input packet (query needs too much out of it) */
- #define GMZ 7 /* get my zone */
- #define GZL 8 /* get zone list */
- /* big enough? */
- if (ip->p_len < (lapSize+ddpSize+sizeof(struct ATP)))
- goto drop;
- po = ip->p_off + lapSize + ddpSize;
- bcopy(po, &zipatp, sizeof(zipatp));
- if (zipatp.a.control != atpReqCode ||
- (zipatp.a.bitmap & 0x1) == 0 || /* at least 1 packet */
- (zipatp.c[4] != GMZ && zipatp.c[4] != GZL) ||
- zipatp.c[5] != 0)
- goto drop;
- zap = (union zipatp *)po;
- po += sizeof(zipatp); /* move ahead */
- zap->a.control = atpRspCode|atpEOM; /*rsp+EOM */
- zap->a.bitmap = 0; /* set seq to match bitmap */
- /* tid already set */
- len = 0;
- switch (zipatp.c[4]) {
- case GMZ:
- zap->c[4] = 0;
- /* Find the zone for the interface request came in on */
- /* cck: modify to find the zone for the source network */
- /* of the packet that came in */
- for (ar = &aroute[0]; ar < &aroute[NAROUTE]; ++ar)
- if (ar->net == ddp.srcNet)
- break;
- if (ar == &aroute[NAROUTE] || ar->zone == 0)
- goto drop;
- pi = azone[ar->zone];
- zl = *pi + 1;
- bcopy(pi, po, zl); /* get zone */
- len += zl; /* and move ptr */
- zap->s[3] = 1; /* set count */
- break;
- case GZL:
- if (conf.flags & conf_stayinzone)
- break;
- /* not clear which bit "lastflag" is */
- zap->c[4] = 0xff;
- /* first index is 1 */
- for (fzones = 0, zi=zipatp.s[3]; azone[zi] ; ++zi) {
- if (zi == allzones)
- continue;
- pi = azone[zi];
- zl = *pi + 1;
- /* enable this if azone is defined larger than atpMaxData */
- if (len + zl > 512) { /* less than maxsize */
- zap->c[4] = 0; /* clear lastflag */
- break;
- }
- bcopy(pi, po, zl);
- fzones++; /* increment count */
- po += zl;
- len += zl;
- }
- zap->s[3] = fzones; /* set count */
- break;
- }
- ip->p_len = lapSize+ddpSize+sizeof(zipatp)+len;
- ddpreply(ip, zipSkt);
- return;
- drop:
- K_PFREE(ip);
- }
-
- zipinput(z, zlen,ia)
- struct ZIP *z;
- int zlen;
- long ia;
- {
- register u_char *pi, *po, *zn;
- register struct aroute *ar;
- register count, i, len;
- int j;
- u_short *sp;
- struct pbuf *op;
- union {
- u_short s;
- u_char c[2];
- } u;
-
- zlen -= sizeof(struct ZIP);
- if (zlen <= 0) /* bad or empty */
- return;
- if (z->command == zipQuery)
- goto query;
- if (z->command == zipReply)
- goto reply;
- #ifdef notdef
- if (z->command == zipTakedown)
- goto takedown;
- #endif
- return;
- reply:
- /* assume (ha) that length is right */
- pi = (u_char *)(z+1); /* point past header */
- j = z->count;
- while (j-- != 0) {
- u.c[0] = *pi++; /* network */
- u.c[1] = *pi++;
- zn = pi; /* remeber zone name */
- pi += ((*pi)+1); /* skip past zone name */
- for (ar = &aroute[0] ; ar < &aroute[NAROUTE]; ++ar) {
- if (u.s != ar->net)
- continue;
- if (ar->zone == 0)
- ar->zone = newzone(zn);
- break; /* break anyway since already zipped */
- }
-
- }
- return;
- query:
- K_PGET(PT_DATA, op);
- if (op == 0)
- return;
- j = z->count;
- sp = (u_short *)(z+1);
- /* setup output packet */
- z = (struct ZIP *)(ia ? m_stuff(op->p_off) : (op->p_off + lapSize+ddpSize));
- z->command = zipReply;
- po = (u_char *)(z+1);
- len = sizeof(struct ZIP);
- for (count = 0; j && len < 512 ; j--) {
- u.s = i = *sp++; /* network */
- for (ar = &aroute[0]; ar < &aroute[NAROUTE] ; ++ar) {
- if (i == ar->net)
- break;
- }
- if (ar >= &aroute[NAROUTE] || ar->zone == 0)
- continue; /* no match */
- count++; /* found one */
- pi = azone[ar->zone];
- *po++ = u.c[0]; /* copy in network */
- *po++ = u.c[1];
- bcopy(pi, po, *pi + 1); /* copy in zone */
- po += (*pi + 1); /* string + count */
- len += (*pi + 3); /* string + count + netnumber */
- }
- z->count = count;
- if (ia) {
- kipit(op, ia, aaZONEQ, len);
- } else {
- op->p_len = lapSize + ddpSize + len;
- ddpreply(op, zipSkt);
- }
- return;
- }
-
-
- kipit(p, ia, type, len)
- struct pbuf *p;
- long ia;
- int type;
- int len;
- {
- register struct aaconf *m;
- struct udp u;
-
- m = (struct aaconf *)(p->p_off + sizeof (struct ip) + sizeof u);
- m->magic = aaMagic;
- m->type = type;
- m->flags = 0;
- m->count = len;
- m->ipaddr = conf.ipaddr;
- u.src = u.dst = aaPort;
- u.length = len + aaconfMinSize + sizeof u;
- u.checksum = 0;
- #ifdef SNMP
- mib_udp.udpOutDatagrams++;
- #endif
- *(struct udp *)(p->p_off + sizeof (struct ip)) = u;
- p->p_len = u.length + sizeof (struct ip);
- setiphdr(p, ia);
- routeip(p, 0, 0);
- }
-